home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Graphics Unleashed
/
PC Graphics Unleashed.iso
/
ch21
/
ffd3d.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-30
|
13KB
|
612 lines
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>
#include <math.h>
#include <alloc.h>
#define TOL 0.0005
#define PI 3.14159265358979323846
#define X_AXIS 1
#define Y_AXIS 2
#define Z_AXIS 3
typedef struct {
float far x,y,z;
} POINT3D;
typedef struct {
int x,y;
} POINTint;
/* World Limits in 2D */
float WXleft;
float WXright;
float WYtop;
float WYbottom;
/* Device Limits */
int DXmin;
int DYmin;
int DYmax;
int DXmax;
/* Rotations for 3D View in Radians*/
float RX;
float RY;
float RZ;
float COSRX;
float SINRX;
float COSRY;
float SINRY;
float COSRZ;
float SINRZ;
void InitGraphics(void);
float DegToRad(float deg);
float RadToDeg(float rad);
POINT3D World3DToWorld2D(POINT3D p);
POINTint World2DToDevice(POINT3D p);
void drawpoint(POINT3D p1);
void drawline(POINT3D p1,POINT3D p2);
void drawaxis(void);
void SetAxesAngles(float rx, float ry, float rz);
void LoadAFile(char *str);
void SaveAFile(char *str);
float Coordinate(int i);
void InitBezierCube(void);
void GetMaxima(float *xi,float *xf,
float *yi,float *yf,
float *zi,float *zf);
void ScaleBezierCube(float x, float y, float z);
void DrawBezierCube(void);
void FreezeBezierCube(float x,float y,float z);
float UVW(float vmin, float vmax, float value);
float Bernstein(float t, int i);
POINT3D GetBezierPoint(float u, float v, float w);
void RotatePatch(int patch, int axis, float deg);
void TranslatePatch(int patch, int axis, float d);
void ScalePatch(int patch, int axis, float s);
void GoFFD(void);
void drawObjects(int n);
void SetView(void);
POINT3D Cube[4][4][4];
POINT3D far *Object;
POINT3D far *Object2;
#define MAXFACES 600 // object may have up to 2000 faces
// COMPILE USING LARGE MEMORY MODEL
int PointNum;
float XS,YS,ZS;
void main()
{
POINT3D p;
int i, loop;
float xmin, xmax,
ymin, ymax,
zmin, zmax;
if((Object = (POINT3D *)farcalloc(3*MAXFACES, sizeof(POINT3D))) == NULL) {
closegraph();
printf("ERROR: Can't allocate database!\n");
exit(1);
}
if((Object2 = (POINT3D *)farcalloc(3*MAXFACES, sizeof(POINT3D))) == NULL) {
closegraph();
printf("ERROR: Can't allocate database!\n");
exit(1);
}
LoadAFile("bottle.raw");
//LoadAFile("plate.raw");
InitGraphics();
setbkcolor(WHITE);
setcolor(BROWN);
cleardevice();
/* World Limits */
WXleft = -1.4;
WXright = 1.4;
WYtop = 1.4;
WYbottom = -1.4;
InitBezierCube();
GetMaxima(&xmin,&xmax,&ymin,&ymax,&zmin,&zmax);
ScaleBezierCube(xmax, ymax, zmax);
FreezeBezierCube(xmax,ymax,zmax);
SetView();
drawObjects(1);
DrawBezierCube();
for(loop=0;loop<10;loop++) {
InitBezierCube();
ScaleBezierCube(xmax, ymax, zmax);
// ANIMATION COMMANDS
//USE WITH BOTTLE.RAW
RotatePatch(3, Z_AXIS, loop*5.0);
TranslatePatch(3, Y_AXIS, 0.5);
TranslatePatch(3, X_AXIS,-0.1*loop);
RotatePatch(0, Z_AXIS, -loop*5.0);
TranslatePatch(0, Y_AXIS, -0.5);
TranslatePatch(0, X_AXIS, -0.1*loop);
/*
// USE WITH PLATE.RAW
RotatePatch(3, Y_AXIS, loop*9.0);
RotatePatch(2, Y_AXIS, loop*4.5);
RotatePatch(1, Y_AXIS, loop*2.0);
*/
// END OF ANIMATION COMMANDS
GoFFD();
clearviewport();
drawaxis();
drawObjects(2);
DrawBezierCube();
}
printf("\7");
getch();
closegraph();
}
/* /////////////////////////////////////////////////////// */
void SetView(void) {
int d;
DXmin = 0.0;
DYmin = 0.0;
DYmax = getmaxy();
DXmax = getmaxy();
d = (getmaxx() - getmaxy())/2;
setviewport(d,0,getmaxy()+d,getmaxy(),1);
SetAxesAngles(20, -15, -5);
drawaxis();
}
void drawObjects(int n) {
int i;
setcolor(BROWN);
if (n==1)
for(i=0;i<PointNum;i+=3) {
drawline(Object[i],Object[i+1]);
drawline(Object[i+1],Object[i+2]);
drawline(Object[i+2],Object[i]);
}
else
for(i=0;i<PointNum;i+=3) {
drawline(Object2[i],Object2[i+1]);
drawline(Object2[i+1],Object2[i+2]);
drawline(Object2[i+2],Object2[i]);
}
}
void GoFFD(void) {
int i;
float Xuvw, Yuvw, Zuvw;
for(i=0;i<PointNum;i++) {
Xuvw = UVW(-XS, XS, Object[i].x);
Yuvw = UVW(-YS, YS, Object[i].y);
Zuvw = UVW(-ZS, ZS, Object[i].z);
Object2[i] = GetBezierPoint(Xuvw, Yuvw, Zuvw);
}
}
void ScalePatch(int patch, int axis, float s){
int i,k;
for(k=0;k<4;k++)
for(i=0;i<4;i++)
switch(axis) {
case X_AXIS: Cube[i][patch][k].x *= s; break;
case Y_AXIS: Cube[i][patch][k].y *= s; break;
case Z_AXIS: Cube[i][patch][k].z *= s; break;
}
}
void TranslatePatch(int patch, int axis, float d){
int i,k;
for(k=0;k<4;k++)
for(i=0;i<4;i++)
switch(axis) {
case X_AXIS: Cube[i][patch][k].x += d; break;
case Y_AXIS: Cube[i][patch][k].y += d; break;
case Z_AXIS: Cube[i][patch][k].z += d; break;
}
}
void RotatePatch(int patch, int axis, float deg) {
float xc=0.0, yc=0.0, zc=0.0;
float COS, SIN;
int i,j,k;
POINT3D p, ptemp;
deg = DegToRad(deg);
COS = cos(deg);
SIN = sin(deg);
//find centroid of patch
for(k=0;k<4;k++)
for(i=0;i<4;i++) {
xc += Cube[i][patch][k].x;
yc += Cube[i][patch][k].y;
zc += Cube[i][patch][k].z;
}
//divide by 16 to get center (average)
xc /= 16.0;
yc /= 16.0;
zc /= 16.0;
// translate center of patch to origin
for(k=0;k<4;k++)
for(i=0;i<4;i++) {
Cube[i][patch][k].x -= xc;
Cube[i][patch][k].y -= yc;
Cube[i][patch][k].z -= zc;
}
// now that center of patch is at origin, rotate about axis
for(k=0;k<4;k++)
for(i=0;i<4;i++) {
p = Cube[i][patch][k];
switch(axis) {
case X_AXIS:
ptemp.x = p.x;
ptemp.y = COS*p.y - SIN*p.z;
ptemp.z = SIN*p.y + COS*p.z;
Cube[i][patch][k] = ptemp;
break;
case Y_AXIS:
ptemp.x = COS*p.x + SIN*p.z;
ptemp.y = p.y;
ptemp.z = -SIN*p.x + COS*p.z;
Cube[i][patch][k] = ptemp;
break;
case Z_AXIS:
ptemp.x = COS*p.x - SIN*p.y;
ptemp.y = SIN*p.x + COS*p.y;
ptemp.z = p.z;
Cube[i][patch][k] = ptemp;
break;
}
}
// translate center of patch back to original place
for(k=0;k<4;k++)
for(i=0;i<4;i++) {
Cube[i][patch][k].x += xc;
Cube[i][patch][k].y += yc;
Cube[i][patch][k].z += zc;
}
}
float UVW(float vmin, float vmax, float value) {
return( (value - vmin)/(vmax - vmin) );
}
float Bernstein(float t, int i) {
float v;
switch(i) {
case 0: v = pow((1.0 - t),3); break;
case 1: v = 3 * t * pow((1.0 - t),2); break;
case 2: v = 3 * pow(t,2) * (1.0 - t); break;
case 3: v = pow(t,3); break;
}
return(v);
}
POINT3D GetBezierPoint(float u, float v, float w) {
int i,j,k;
POINT3D q;
float factor, wk, vk, wkvk;
q.x = q.y = q.z = 0.0;
for(k=0;k<4;k++) {
wk = Bernstein(w,k);
for(j=0;j<4;j++) {
vk = Bernstein(v,j);
wkvk = wk * vk;
for(i=0;i<4;i++) {
factor = Bernstein(u,i) * wkvk;
q.x += Cube[i][j][k].x * factor;
q.y += Cube[i][j][k].y * factor;
q.z += Cube[i][j][k].z * factor;
}
}
}
return(q);
}
void FreezeBezierCube(float x,float y,float z) {
XS = x;
YS = y;
ZS = z;
}
void GetMaxima(float *xi,float *xf,
float *yi,float *yf,
float *zi,float *zf) {
int i;
float x1=1e6,x2=-1e6,
y1=1e6,y2=-1e6,
z1=1e6,z2=-1e6;
for(i=0;i<PointNum;i++) {
if(Object[i].x < x1)
x1 = Object[i].x;
else
if(Object[i].x > x2)
x2 = Object[i].x;
if(Object[i].y < y1)
y1 = Object[i].y;
else
if(Object[i].y > y2)
y2 = Object[i].y;
if(Object[i].z < z1)
z1 = Object[i].z;
else
if(Object[i].z > z2)
z2 = Object[i].z;
}
*xi = x1;
*xf = x2;
*yi = y1;
*yf = y2;
*zi = z1;
*zf = z2;
}
float Coordinate(int i) {
switch(i) {
case 0: return(-1.0);
case 1: return(-0.3);
case 2: return( 0.3);
default: return( 1.0); //case 3
}
}
void InitBezierCube(void) {
int i,j, k;
for(k=0;k<4;k++)
for(j=0;j<4;j++)
for(i=0;i<4;i++) {
Cube[i][j][k].x = Coordinate(i);
Cube[i][j][k].y = Coordinate(j);
Cube[i][j][k].z = Coordinate(k);
}
}
void ScaleBezierCube(float x, float y, float z) {
int i,j, k;
for(k=0;k<4;k++)
for(j=0;j<4;j++)
for(i=0;i<4;i++) {
Cube[i][j][k].x *= x;
Cube[i][j][k].y *= y;
Cube[i][j][k].z *= z;
}
}
void DrawBezierCube(void) {
int i,j, k;
setlinestyle(DOTTED_LINE,1, 1);
setcolor(RED);
for(k=0;k<4;k++)
for(j=0;j<4;j++)
for(i=0;i<4;i++)
drawpoint(Cube[i][j][k]);
for(j=0;j<4;j++)
for(k=0;k<4;k++)
for(i=0;i<3;i++)
drawline(Cube[i][j][k],Cube[i+1][j][k]);
for(j=0;j<4;j++)
for(i=0;i<4;i++)
for(k=0;k<3;k++)
drawline(Cube[i][j][k],Cube[i][j][k+1]);
for(k=0;k<4;k++)
for(i=0;i<4;i++)
for(j=0;j<3;j++)
drawline(Cube[i][j][k],Cube[i][j+1][k]);
setlinestyle(SOLID_LINE,1, 1);
}
void SaveAFile(char *str)
{
FILE *fptr;
int i;
if ((fptr = fopen(str,"w+t")) == NULL)
printf("\7");
else {
for(i=0;i<PointNum;i+=3)
fprintf(fptr,"%g %g %g %g %g %g %g %g %g\n",
Object2[i].x, Object2[i].y, Object2[i].z,
Object2[i+1].x, Object2[i+1].y, Object2[i+1].z,
Object2[i+2].x, Object2[i+2].y, Object2[i+2].z);
fclose(fptr);
}
}
void LoadAFile(char *str)
{
FILE *fptr;
float x,y,z;
int bnum;
if ( (fptr = fopen(str,"r")) == NULL) {
printf("\7");
}
else {
bnum = -1;
while (!feof(fptr)) {
if ((fscanf(fptr,"%f",&x) > 0) &&
(fscanf(fptr,"%f",&y) > 0) &&
(fscanf(fptr,"%f",&z) > 0)) {
bnum++;
if(bnum < MAXFACES*3) {
Object[bnum].x = x;
Object[bnum].y = y;
Object[bnum].z = z;
}
}
}
fclose(fptr);
PointNum = bnum+1;
}
}
void InitGraphics(void)
{
int gdriver = DETECT, gmode, errorcode;
initgraph(&gdriver, &gmode, "");
if (gdriver != VGA) {
printf("VGA graphics card required.\n");
exit(1);
}
errorcode = graphresult();
if (errorcode != grOk) /* an error occurred */
{
printf("Graphics error: %s\n", grapherrormsg(errorcode));
printf("Press any key to halt:");
getch();
exit(1); /* terminate with an error code */
}
setviewport(0,0,getmaxx(),getmaxy(),1);
}
float DegToRad(float deg)
{
return(deg*PI/180.0);
}
float RadToDeg(float rad)
{
return(rad*180.0/PI);
}
void SetAxesAngles(float rx, float ry, float rz) {
RX = DegToRad(rx);
RY = DegToRad(ry);
RZ = DegToRad(rz);
COSRX = cos(RX);
SINRX = sin(RX);
COSRY = cos(RY);
SINRY = sin(RY);
COSRZ = cos(RZ);
SINRZ = sin(RZ);
}
POINT3D World3DToWorld2D(POINT3D p)
{
POINT3D ptemp;
ptemp = p;
if (RX) {
ptemp.x = p.x;
ptemp.y = COSRX*p.y - SINRX*p.z;
ptemp.z = SINRX*p.y + COSRX*p.z;
p = ptemp;
}
if (RY) {
ptemp.x = COSRY*p.x + SINRY*p.z;
ptemp.y = p.y;
ptemp.z = -SINRY*p.x + COSRY*p.z;
p = ptemp;
}
if (RZ) {
ptemp.x = COSRZ*p.x - SINRZ*p.y;
ptemp.y = SINRZ*p.x + COSRZ*p.y;
ptemp.z = p.z;
}
if (fabs(ptemp.x) < TOL) ptemp.x = 0.0;
if (fabs(ptemp.y) < TOL) ptemp.y = 0.0;
if (fabs(ptemp.z) < TOL) ptemp.z = 0.0;
return(ptemp);
}
POINTint World2DToDevice(POINT3D p)
{
POINTint ptemp;
ptemp.x = (WXleft-p.x)*(DXmax-DXmin)/(WXleft-WXright) + DXmin + 0.5;
ptemp.y = (WYtop-p.y)*(DYmax-DYmin)/(WYtop-WYbottom) + DYmin + 0.5;
return(ptemp);
}
void drawpoint(POINT3D p1)
{
/* draws a 3D point */
POINTint p2;
p1.z = -p1.z;
p2 = World2DToDevice(World3DToWorld2D(p1));
rectangle(p2.x - 2, p2.y - 2, p2.x + 2, p2.y + 2);
}
void drawline(POINT3D p1,POINT3D p2)
{
/* draws a 3D line */
POINTint p11,p22;
p1.z = -p1.z;
p2.z = -p2.z;
p11 = World2DToDevice(World3DToWorld2D(p1));
p22 = World2DToDevice(World3DToWorld2D(p2));
line(p11.x,p11.y,p22.x,p22.y);
}
void drawaxis(void) {
POINT3D p1,p2;
p1.x = p1.y = p1.z = 0;
p2.x = 1; p2.y = 0; p2.z=0;
setcolor(RED);
drawline(p1,p2);
p2.x = 0; p2.y = 1; p2.z=0;
setcolor(GREEN);
drawline(p1,p2);
p2.x = 0; p2.y = 0; p2.z=1;
setcolor(BLUE);
drawline(p1,p2);
setcolor(WHITE);
}